package io.renren.modules.member.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.LocalDateUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.SnowFlake;
import io.renren.modules.member.dao.ExamDao;
import io.renren.modules.member.dto.ExamDto;
import io.renren.modules.member.entity.ExamEntity;
import io.renren.modules.member.entity.MemberEntity;
import io.renren.modules.member.enums.AchivTotalJudgeEnums;
import io.renren.modules.member.enums.SexEnums;
import io.renren.modules.member.enums.ShapeLevelEnums;
import io.renren.modules.member.enums.SportEnums;
import io.renren.modules.member.service.*;
import io.renren.modules.member.vo.ExamVO;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service("examService")
public class ExamServiceImpl extends ServiceImpl<ExamDao, ExamEntity> implements ExamService {

    private final Logger logger = LoggerFactory.getLogger(ExamServiceImpl.class);

    @Autowired
    private CommQueryService commQueryService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private StandardBmiService standardBmiService;

    @Autowired
    private StandardCommService standardCommService;

    @Autowired
    private StandardTotalService standardTotalService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        return commQueryService.queryPageExam(params);
    }

    private List<ExamVO> findByCondition(Map<String, Object> params) {
        return commQueryService.queryAllExam(params);
    }

    public List<List<String>> downExcelByCondition(Map<String, Object> params, List<String> titles) {
        String[] titleArr = {"日期", "编号", "姓名", "性别", "出生日期", "年龄", "身高(cm)", "体重(kg)", "BMI", "是否合格", "引体向上", "曲臂悬垂(秒)", "成绩", "俯卧撑", "成绩", "仰卧起坐", "成绩",
                "蛇形跑(秒)", "成绩", "中长跑(分:秒)", "成绩", "成绩总评", "等级评定"};
        titles.addAll(Arrays.asList(titleArr));
        List<ExamVO> entities = findByCondition(params);
        if (CollectionUtils.isEmpty(entities)) {
            return new ArrayList<>();
        }
        return entities.stream().map(e -> {
            List<String> rowValues = new ArrayList<>();
            rowValues.add(Objects.nonNull(e.getExamDate()) ? DateUtils.format(e.getExamDate()) : "");
            rowValues.add(e.getStudentCode());
            rowValues.add(e.getName());
            rowValues.add(SexEnums.getTextFromCode(e.getSex()));
            rowValues.add(Objects.nonNull(e.getBirthday()) ? DateUtils.format(e.getBirthday()) : "");
            rowValues.add(Optional.ofNullable(e.getAge()).orElse(0).toString());
            rowValues.add(Optional.ofNullable(e.getHeight()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getWeight()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getBmi()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(ShapeLevelEnums.getTextFromCode(e.getShapeLevel()));
            rowValues.add(Optional.ofNullable(e.getLeadUp()).orElse(0).toString());
            rowValues.add(Optional.ofNullable(e.getCrankArm()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getCrankArmScore()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getPushUp()).orElse(0).toString());
            rowValues.add(Optional.ofNullable(e.getPushUpScore()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getSitUp()).orElse(0).toString());
            rowValues.add(Optional.ofNullable(e.getSitUpScore()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getSnakeRun()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getSnakeRunScore()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getMiddleRun()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getMiddleRunScore()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(Optional.ofNullable(e.getTotalScore()).orElse(BigDecimal.ZERO).toString());
            rowValues.add(AchivTotalJudgeEnums.getTextFromCode(e.getLevel()));
            return rowValues;
        }).collect(Collectors.toList());
    }

    public Integer batchSaveExcelExam(List<List<Object>> list, Map<String, Integer> position) {
        List<ExamEntity> entities = list.stream().map(e -> {
            ExamEntity entity = new ExamEntity();
            entity.setStudentCode(getValue(e, position, "studentCode", String.class));
            entity.setHeight(getValue(e, position, "height", BigDecimal.class));
            entity.setWeight(getValue(e, position, "weight", BigDecimal.class));
            entity.setExamDate(getValue(e, position, "examDate", Date.class));
            entity.setLeadUp(getValue(e, position, "leadUp", Integer.class));
            entity.setCrankArm(getValue(e, position, "crankRrm", BigDecimal.class));
            entity.setPushUp(getValue(e, position, "pushUp", Integer.class));
            entity.setSitUp(getValue(e, position, "sitUp", Integer.class));
            entity.setSnakeRun(getValue(e, position, "snakeRun", BigDecimal.class));
            entity.setMiddleRun(getFrom(getValue(e, position, "middleRun", String.class)));
            return entity;
        }).collect(Collectors.toList());
        int count = 0;
        for (ExamEntity entity : entities) {
            try {
                ExamEntity result = saveOrUpdateNonNullField(entity);
                if (Objects.nonNull(result)) {
                    count ++;
                }
            } catch (Exception e) {
                logger.error("Excel导入保存考试数据失败：{}", entity.toString());
                logger.error("Excel导入保存考试数据失败信息：{}", e);
            }
        }
        return count;
    }

    private ExamEntity saveOrUpdateNonNullField(ExamEntity entity) {
        if (StringUtils.isBlank(entity.getStudentCode())) {
            return null;
        }
        ExamEntity oldEntity = baseMapper.findByStuCodeAndExdate(entity.getStudentCode(), entity.getExamDate());
        if (Objects.nonNull(oldEntity)) {
            oldEntity.setHeight(Optional.ofNullable(entity.getHeight()).orElse(oldEntity.getHeight()));
            oldEntity.setWeight(Optional.ofNullable(entity.getWeight()).orElse(oldEntity.getWeight()));
            oldEntity.setLeadUp(Optional.ofNullable(entity.getLeadUp()).orElse(oldEntity.getLeadUp()));
            oldEntity.setCrankArm(Optional.ofNullable(entity.getCrankArm()).orElse(oldEntity.getCrankArm()));
            oldEntity.setPushUp(Optional.ofNullable(entity.getPushUp()).orElse(oldEntity.getPushUp()));
            oldEntity.setSitUp(Optional.ofNullable(entity.getSitUp()).orElse(oldEntity.getSitUp()));
            oldEntity.setSnakeRun(Optional.ofNullable(entity.getSnakeRun()).orElse(oldEntity.getSnakeRun()));
            BigDecimal oldMiddeRun = Optional.ofNullable(oldEntity.getMiddleRun()).orElse(BigDecimal.ZERO);
            BigDecimal newMiddeRun = Optional.ofNullable(entity.getMiddleRun()).orElse(BigDecimal.ZERO);
            if (newMiddeRun.compareTo(oldMiddeRun) == 1) {
                oldEntity.setMiddleRun(Optional.ofNullable(newMiddeRun).orElse(oldEntity.getMiddleRun()));
                oldEntity.setCircle(entity.getCircle());
            }
            oldEntity.setUpdateDate(new Date());
            // 计算成绩
            calcScore(oldEntity);
            baseMapper.updateById(oldEntity);
            return oldEntity;
        } else {
            entity.setExamCode(SnowFlake.createSnowFlake().nextIdString());
            entity.setCreateDate(new Date());
            // 计算成绩
            calcScore(entity);
            baseMapper.insert(entity);
            return entity;
        }
    }

    private BigDecimal getFrom(String target) {
        if (StringUtils.isBlank(target)) {
            return BigDecimal.ZERO;
        }
        if (target.contains(":")) {
            return new BigDecimal(target.replace(":", "."));
        }
        return new BigDecimal(target);
    }

    public Boolean saveOrUpdateExam(ExamEntity entity) {
        if (StringUtils.isBlank(entity.getStudentCode())) {
            return Boolean.FALSE;
        }
        if (Objects.nonNull(entity.getId())) {
            entity.setUpdateDate(new Date());
            // 计算成绩
            calcScore(entity);
            baseMapper.updateById(entity);
        } else {
            entity.setExamCode(SnowFlake.createSnowFlake().nextIdString());
            entity.setCreateDate(new Date());
            // 计算成绩
            calcScore(entity);
            baseMapper.insert(entity);
        }
//        ExamEntity oldEntity = baseMapper.findByStuCodeAndExdate(entity.getStudentCode(), entity.getExamDate());
//        if (Objects.nonNull(oldEntity)) {
//            entity.setId(oldEntity.getId());
//            BeanUtils.copyProperties(entity, oldEntity);
//            oldEntity.setUpdateDate(new Date());
//            // 计算成绩
//            calcScore(oldEntity);
//            baseMapper.updateById(oldEntity);
//        } else {
//            entity.setExamCode(SnowFlake.createSnowFlake().nextIdString());
//            entity.setCreateDate(new Date());
//            // 计算成绩
//            calcScore(entity);
//            baseMapper.insert(entity);
//        }
        return Boolean.TRUE;
    }

    /**
     * 计算各项成绩和总成绩
     * @param entity
     */
    private void calcScore(ExamEntity entity) {
        MemberEntity memberEntity = memberService.findByStudentCode(entity.getStudentCode());
        if (Objects.isNull(memberEntity)) {
            return;
        }
        // 计算年龄
        entity.setAge(calcAge(entity, memberEntity));
        entity.setShapeLevel(standardBmiService.getBmiSorce(entity, memberEntity));
        if (StringUtils.equals("1", memberEntity.getSex())) {
            entity.setCrankArmScore(standardCommService.getLeadUpScore(entity, memberEntity));
        } else {
            entity.setCrankArmScore(standardCommService.getCrankArmScore(entity, memberEntity));
        }
        entity.setPushUpScore(standardCommService.getPushUpScore(entity, memberEntity));
        entity.setSitUpScore(standardCommService.getSitUpScore(entity, memberEntity));
        entity.setSnakeRunScore(standardCommService.getSnakeScore(entity, memberEntity));
        entity.setMiddleRunScore(standardCommService.getMiddleRunScore(entity, memberEntity));
        entity.setTotalScore(calcTotalScore(entity, memberEntity));
        entity.setLevel(standardTotalService.getLevel(entity, memberEntity));
    }

    private Integer calcAge(ExamEntity entity, MemberEntity memberEntity) {
        if (Objects.nonNull(memberEntity.getBirthday())) {
            LocalDate begin = LocalDateUtils.getLocalDateFromDate(memberEntity.getBirthday());
            LocalDate end = LocalDateUtils.getLocalDateFromDate(entity.getExamDate());
            return begin.until(end).getYears();
        }
        return 0;
    }

    private BigDecimal calcTotalScore(ExamEntity entity, MemberEntity memberEntity) {
        BigDecimal totalScore = BigDecimal.ZERO;
        // 男：引体向上；女：曲臂悬垂
        if (StringUtils.equals(memberEntity.getSex(), "1")) {
            totalScore = totalScore.add(entity.getCrankArmScore());
        } else {
            totalScore = totalScore.add(entity.getCrankArmScore());
        }
        // 俯卧撑
        totalScore = totalScore.add(entity.getPushUpScore());
        // 仰卧起坐
        totalScore = totalScore.add(entity.getSitUpScore());
        // 蛇形跑
        totalScore = totalScore.add(entity.getSnakeRunScore());
        // 中长跑
        totalScore = totalScore.add(entity.getMiddleRunScore());
        return totalScore;
    }

    /**
     * 从list中获取对应属性值
     * @param list 属性值
     * @param position 属性对应list中的位置映射
     * @param fieldName 属性名称
     * @param clazz 返回数据类型
     * @return
     */
    private <T> T getValue(List<Object> list, Map<String, Integer> position, String fieldName, Class clazz) {
        Integer index = position.get(fieldName);
        if (Objects.isNull(index)) {
            return null;
        }
        if (index >= list.size()) {
            return null;
        }
        String result = String.valueOf(list.get(index));
        if (StringUtils.equals(result, "NULL") || StringUtils.equals(result, "null")) {
            result = null;
        }
        if (StringUtils.isBlank(result)) {
            return null;
        }
        result = result.trim();
        if (clazz == String.class) {
            return (T) result.toString();
        }
        if (clazz == Integer.class) {
            return (T) new Integer(result);
        }
        if (clazz == Long.class) {
            return (T) new Long(result);
        }
        if (clazz == BigDecimal.class) {
            return (T) new BigDecimal(result);
        }
        if (clazz == Date.class) {
            return (T) DateUtils.dateFrom(result);
        }
        logger.info("数据元素类型无法解析：{}", result);
        return null;
    }

    public ExamEntity saveOneAchiv(ExamDto dto) {
        ExamEntity entity = new ExamEntity();
        entity.setStudentCode(dto.getStudentCode());
        entity.setExamDate(dto.getDate());
        if (StringUtils.equals(SportEnums.LEAD_UP.getCode(), dto.getType())) {
            entity.setLeadUp(dto.getAchieve().intValue());
        } else if (StringUtils.equals(SportEnums.CRANK_ARM.getCode(), dto.getType())) {
            // 客户端传过来的是毫秒
            entity.setCrankArm(dto.getAchieve().multiply(new BigDecimal("0.001")));
        } else if (StringUtils.equals(SportEnums.PUSH_UP.getCode(), dto.getType())) {
            entity.setPushUp((dto.getAchieve().intValue()));
        } else if (StringUtils.equals(SportEnums.SIT_UP.getCode(), dto.getType())) {
            entity.setSitUp((dto.getAchieve().intValue()));
        } else if (StringUtils.equals(SportEnums.SNAKE_RUN.getCode(), dto.getType())) {
            // 客户端传过来的是毫秒
            entity.setSnakeRun(dto.getAchieve().multiply(new BigDecimal("0.001")));
        } else if (StringUtils.equals(SportEnums.MIDDLE_RUN.getCode(), dto.getType())) {
            int minute = dto.getAchieve().intValue() / 1000 / 60;
            int second = (dto.getAchieve().intValue() / 1000) % 60;
            entity.setMiddleRun(new BigDecimal(minute + "." + second));
            entity.setCircle(dto.getCircle());
        }
        return saveOrUpdateNonNullField(entity);
    }

    public void batchStrSave(List<String> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        Map<String, ExamEntity> map = new HashMap<>();
        String[] params = null;
        for(String str : list) {
            params = str.split("`");
            if (params.length < 4) {
                continue;
            }
            if (StringUtils.isBlank(params[0])
                    || StringUtils.isBlank(params[1])
                    || StringUtils.isBlank(params[2])
                    || StringUtils.isBlank(params[3])) {
                continue;
            }
            // 时间字符长度大于10则只截取年月日
            if (params[0].length() > 10) {
                params[0] = params[0].substring(0, 10);
            }
            String key = params[0] + "`" + params[1];
            ExamEntity entity = map.get(key);
            if (Objects.isNull(entity)) {
                entity = new ExamEntity();
                entity.setStudentCode(params[1]);
                entity.setExamDate(DateUtils.stringToDate(params[0], DateUtils.DATE_PATTERN));
                map.put(key, entity);
            }
            if (StringUtils.equals(SportEnums.LEAD_UP.getCode(), params[2])) {
                entity.setLeadUp(new BigDecimal(params[3]).intValue());
            } else if (StringUtils.equals(SportEnums.CRANK_ARM.getCode(), params[2])) {
                entity.setCrankArm(new BigDecimal(params[3]));
            } else if (StringUtils.equals(SportEnums.PUSH_UP.getCode(), params[2])) {
                entity.setPushUp((new BigDecimal(params[3]).intValue()));
            } else if (StringUtils.equals(SportEnums.SIT_UP.getCode(), params[2])) {
                entity.setSitUp((new BigDecimal(params[3]).intValue()));
            } else if (StringUtils.equals(SportEnums.SNAKE_RUN.getCode(), params[2])) {
                entity.setSnakeRun(new BigDecimal(params[3]));
            } else if (StringUtils.equals(SportEnums.MIDDLE_RUN.getCode(), params[2])) {
                // 上传文件的时间是毫秒
                int minute = new BigDecimal(params[3]).intValue() / 1000 / 60;
                int second = (new BigDecimal(params[3]).intValue() / 1000) % 60;
                entity.setMiddleRun(new BigDecimal(minute + "." + second));
                if (params.length > 4) {
                    entity.setCircle(Integer.parseInt(params[4]));
                } else {
                    entity.setCircle(1);
                }
            }
        }

        for (ExamEntity entity : map.values()) {
            entity.setExamCode(SnowFlake.createSnowFlake().nextIdString());
            saveOrUpdateNonNullField(entity);
        }
    }



}
